#include "disasm.h"
#include "hexfile.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

void disamble(void) {
  // uint32_t pc = 0x1898;
  uint32_t pc = 0;
  int rn;

  while (pc < 65536) {
    int opcode = get_value(pc);
    if (opcode == 0x00) {
      uint32_t n = 1;
      while ((pc + n < 65536) && (get_value(pc + n) == 0x00)) {
        n++;
      }
      if (n == 1) {
        printf("%04x\tNOP\n", pc);
      } else {
        printf("%04x-%04x\tNOP\n", pc, pc + n - 1);
      }
      pc += n;
      continue;
    }
    printf("%04x\t", pc);
    switch (opcode) {

    case 0x28:
    case 0x29:
    case 0x2A:
    case 0x2B:
    case 0x2C:
    case 0x2D:
    case 0x2E:
    case 0x2F:
      rn = opcode & 0x03;
      printf("ADD A,R%d", rn);
      pc++;
      break;
    case 0x25:
      printf("ADD A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x26:
    case 0x27:
      rn = opcode & 0x01;
      printf("ADD A,@R%d", rn);
      pc++;
      break;
    case 0x24:
      printf("ADD A,#%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x38:
    case 0x39:
    case 0x3A:
    case 0x3B:
    case 0x3C:
    case 0x3D:
    case 0x3E:
    case 0x3F:
      rn = opcode & 0x03;
      printf("ADDC A,R%d", rn);
      pc++;
      break;
    case 0x35:
      printf("ADDC A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x36:
    case 0x37:
      rn = opcode & 0x01;
      printf("ADDC A,@R%d", rn);
      pc++;
      break;
    case 0x34:
      printf("ADDC A,#%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x98:
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9E:
    case 0x9F:
      rn = opcode & 0x03;
      printf("SUBB A,R%d", rn);
      pc++;
      break;
    case 0x95:
      printf("SUBB A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x96:
    case 0x97:
      rn = opcode & 0x01;
      printf("SUBB A,@R%d", rn);
      pc++;
      break;
    case 0x94:
      printf("SUBB A,#%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x04:
      printf("INC A");
      pc++;
      break;
    case 0x08:
    case 0x09:
    case 0x0A:
    case 0x0B:
    case 0x0C:
    case 0x0D:
    case 0x0E:
    case 0x0F:
      rn = opcode & 0x03;
      printf("INC R%d", rn);
      pc++;
      break;
    case 0x05:
      printf("INC %02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x06:
    case 0x07:
      rn = opcode & 0x01;
      printf("INC @R%d", rn);
      pc++;
      break;
    case 0xA3:
      printf("INC DPTR");
      pc++;
      break;
    case 0x14:
      printf("DEC A");
      pc++;
      break;
    case 0x18:
    case 0x19:
    case 0x1A:
    case 0x1B:
    case 0x1C:
    case 0x1D:
    case 0x1E:
    case 0x1F:
      rn = opcode & 0x03;
      printf("DEC R%d", rn);
      pc++;
      break;
    case 0x15:
      printf("DEC %02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x16:
    case 0x17:
      rn = opcode & 0x01;
      printf("DEC @R%d", rn);
      pc++;
      break;
    case 0xA4:
      printf("MUL AB");
      pc++;
    case 0x84:
      printf("DIV AB");
      pc++;
      break;
    case 0xD4:
      printf("DA A");
      pc++;
      break;
    case 0x58:
    case 0x59:
    case 0x5A:
    case 0x5B:
    case 0x5C:
    case 0x5D:
    case 0x5E:
    case 0x5F:
      rn = opcode & 0x03;
      printf("ANL A,R%d", rn);
      pc++;
      break;
    case 0x55:
      printf("ANL A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x56:
    case 0x57:
      rn = opcode & 0x01;
      printf("ANL A,@R%d", rn);
      pc++;
      break;
    case 0x54:
      printf("ANL A,#%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x52:
      printf("ANL %02x,A", get_value(pc + 1));
      pc += 2;
      break;
    case 0x53:
      printf("ANL %02x,#%02x", get_value(pc + 1), get_value(pc + 2));
      pc += 3;
      break;
    case 0x48:
    case 0x49:
    case 0x4A:
    case 0x4B:
    case 0x4C:
    case 0x4D:
    case 0x4E:
    case 0x4F:
      rn = opcode & 0x03;
      printf("ORL A,R%d", rn);
      pc++;
      break;
    case 0x45:
      printf("ORL A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x46:
    case 0x47:
      rn = opcode & 0x01;
      printf("ORL A,@R%d", rn);
      pc++;
      break;
    case 0x44:
      printf("ORL A,#%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x42:
      printf("ORL %02x,A", get_value(pc + 1));
      pc += 2;
      break;
    case 0x43:
      printf("ORL %02x,#%02x", get_value(pc + 1), get_value(pc + 2));
      pc += 3;
      break;
    case 0x68:
    case 0x69:
    case 0x6A:
    case 0x6B:
    case 0x6C:
    case 0x6D:
    case 0x6E:
    case 0x6F:
      rn = opcode & 0x03;
      printf("XRL A,R%d", rn);
      pc++;
      break;
    case 0x65:
      printf("XRL A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x66:
    case 0x67:
      rn = opcode & 0x01;
      printf("XRL A,@R%d", rn);
      pc++;
      break;
    case 0x64:
      printf("XRL A,#%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x62:
      printf("XRL %02x,A", get_value(pc + 1));
      pc += 2;
      break;
    case 0x63:
      printf("XRL %02x,#%02x", get_value(pc + 1), get_value(pc + 2));
      pc += 3;
      break;
    case 0xE4:
      printf("CLR A");
      pc++;
      break;
    case 0xF4:
      printf("CPL A");
      pc++;
      break;
    case 0x23:
      printf("RL A");
      pc++;
      break;
    case 0x33:
      printf("RLC A");
      pc++;
      break;
    case 0x03:
      printf("RR A");
      pc++;
      break;
    case 0x13:
      printf("RRC A");
      pc++;
      break;
    case 0xC4:
      printf("SWAP A");
      pc++;
      break;
    case 0xE8:
    case 0xE9:
    case 0xEA:
    case 0xEB:
    case 0xEC:
    case 0xED:
    case 0xEE:
    case 0xEF:
      rn = opcode & 0x03;
      printf("MOV A,R%d", rn);
      pc++;
      break;
    case 0xE5:
      printf("MOV A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xE6:
    case 0xE7:
      rn = opcode & 0x01;
      printf("MOV A,@R%d", rn);
      pc++;
      break;
    case 0x74:
      printf("MOV A,#%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xF8:
    case 0xF9:
    case 0xFA:
    case 0xFB:
    case 0xFC:
    case 0xFD:
    case 0xFE:
    case 0xFF:
      rn = opcode & 0x03;
      printf("MOV R%d,A", rn);
      pc++;
      break;
    case 0xA8:
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAE:
    case 0xAF:
      rn = opcode & 0x03;
      printf("MOV R%d,%02x", rn, get_value(pc + 1));
      pc += 2;
      break;
    case 0x78:
    case 0x79:
    case 0x7A:
    case 0x7B:
    case 0x7C:
    case 0x7D:
    case 0x7E:
    case 0x7F:
      rn = opcode & 0x03;
      printf("MOV R%d,#%02x", rn, get_value(pc + 1));
      pc += 2;
      break;
    case 0xF5:
      printf("MOV %02x,A", get_value(pc + 1));
      pc += 2;
      break;
    case 0x88:
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8E:
    case 0x8F:
      rn = opcode & 0x03;
      printf("MOV %02x,R%d", get_value(pc + 1), rn);
      pc += 2;
      break;
    case 0x85:
      printf("MOV %02x,%02x", get_value(pc + 1), get_value(pc + 2));
      pc += 3;
      break;
    case 0x86:
    case 0x87:
      rn = opcode & 0x01;
      printf("MOV %02x,@R%d", get_value(pc + 1), rn);
      pc += 2;
      break;
    case 0x75:
      printf("MOV %02x,#%02x", get_value(pc + 1), get_value(pc + 2));
      pc += 3;
      break;
    case 0xF6:
    case 0xF7:
      rn = opcode & 0x01;
      printf("MOV @R%d,A", rn);
      pc++;
      break;
    case 0xA6:
    case 0xA7:
      rn = opcode & 0x01;
      printf("MOV @R%d,%02x", rn, get_value(pc + 1));
      pc += 2;
      break;
    case 0x76:
    case 0x77:
      rn = opcode & 0x01;
      printf("MOV @R%d,#%02x", rn, get_value(pc + 1));
      pc += 2;
      break;
    case 0x90:
      printf("MOV DPTR,#%04x", get_value(pc + 1) << 8 | get_value(pc + 2));
      pc += 3;
      break;
    case 0x93:
      printf("MOVC A,@A+DPTR");
      pc++;
      break;
    case 0x83:
      printf("MOVC A,@A+PC");
      pc++;
      break;
    case 0xE2:
    case 0xE3:
      rn = opcode & 0x01;
      printf("MOVX A,@R%d", rn);
      pc++;
      break;
    case 0xE0:
      printf("MOVX A,@DPTR");
      pc++;
      break;
    case 0xF2:
    case 0xF3:
      rn = opcode & 0x01;
      printf("MOVX @R%d,A", rn);
      pc++;
      break;
    case 0xF0:
      printf("MOVX @DPTR,A");
      pc++;
      break;
    case 0xC0:
      printf("PUSH %02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xD0:
      printf("POP %02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xC8:
    case 0xC9:
    case 0xCA:
    case 0xCB:
    case 0xCC:
    case 0xCD:
    case 0xCE:
    case 0xCF:
      rn = opcode & 0x03;
      printf("XCH A,R%d", rn);
      pc += 1;
      break;
    case 0xC5:
      printf("XCH A,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xC6:
    case 0xC7:
      rn = opcode & 0x01;
      printf("XCH A,@R%d", rn);
      pc++;
      break;
    case 0xD6:
    case 0xD7:
      rn = opcode & 0x01;
      printf("XCHD A,@R%d", rn);
      pc++;
      break;
    case 0x12:
      printf("LCALL %04x", get_value(pc + 1) << 8 | get_value(pc + 2));
      pc += 3;
      break;
    case 0x22:
      printf("RET");
      pc++;
      break;
    case 0x32:
      printf("RETI");
      pc++;
      break;
    case 0x02:
      printf("LJMP %04x", get_value(pc + 1) << 8 | get_value(pc + 2));
      pc += 3;
      break;
    case 0x80:
      printf("SJMP %d\t//%04x", (int8_t)get_value(pc + 1),
             pc + 2 + (int8_t)get_value(pc + 1));
      pc += 2;
      break;
    case 0x73:
      printf("JMP @A+DPTR");
      pc++;
      break;
    case 0x60:
      printf("JZ %d\t//%04x", (int8_t)get_value(pc + 1),
             pc + 2 + (int8_t)get_value(pc + 1));
      pc += 2;
      break;
    case 0x70:
      printf("JNZ %d\t//%04x", (int8_t)get_value(pc + 1),
             pc + 2 + (int8_t)get_value(pc + 1));
      pc += 2;
      break;
    case 0x40:
      printf("JC %d\t//%04x", (int8_t)get_value(pc + 1),
             pc + 2 + (int8_t)get_value(pc + 1));
      pc += 2;
      break;
    case 0x50:
      printf("JNC %d\t//%04x", (int8_t)get_value(pc + 1),
             pc + 2 + (int8_t)get_value(pc + 1));
      pc += 2;
      break;
    case 0x20:
      printf("JB %02x,%d", get_value(pc + 1), (int8_t)get_value(pc + 2));
      pc += 3;
      break;
    case 0x30:
      printf("JNB %02x,%d", get_value(pc + 1), (int8_t)get_value(pc + 2));
      pc += 3;
      break;
    case 0x10:
      printf("JBC %02x,%d", get_value(pc + 1), (int8_t)get_value(pc + 2));
      pc += 3;
      break;
    case 0xB5:
      printf("CJNE A,%02x,%d", get_value(pc + 1), (int8_t)get_value(pc + 2));
      pc += 3;
      break;
    case 0xB4:
      printf("CJNE A,#%02x,%d", get_value(pc + 1), (int8_t)get_value(pc + 2));
      pc += 3;
      break;
    case 0xB8:
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBE:
    case 0xBF:
      rn = opcode & 0x03;
      printf("CJNE R%d,#%02x,%d", rn, get_value(pc + 1),
             (int8_t)get_value(pc + 2));
      pc += 3;
      break;
    case 0xB6:
    case 0xB7:
      rn = opcode & 0x01;
      printf("CJNE @R%d,#%02x,%d", rn, get_value(pc + 1),
             (int8_t)get_value(pc + 2));
      pc += 3;
      break;
    case 0xD8:
    case 0xD9:
    case 0xDA:
    case 0xDB:
    case 0xDC:
    case 0xDD:
    case 0xDE:
    case 0xDF:
      rn = opcode & 0x03;
      printf("DJNZ R%d,%d", rn, (int8_t)get_value(pc + 1));
      pc += 2;
      break;
    case 0xD5:
      printf("DJNZ %02x,%d", get_value(pc + 1), (int8_t)get_value(pc + 2));
      pc += 3;
      break;

    case 0xC3:
      printf("CLR C");
      pc++;
      break;
    case 0xC2:
      printf("CLR %02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xD3:
      printf("SETB C");
      pc++;
      break;
    case 0xD2:
      printf("SETB %02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xB3:
      printf("CPL C");
      pc++;
      break;
    case 0xB2:
      printf("CPL %02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x82:
      printf("ANL C,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xB0:
      printf("ANL C,/%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x72:
      printf("ORL C,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xA0:
      printf("ORL C,/%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0xA2:
      printf("MOV C,%02x", get_value(pc + 1));
      pc += 2;
      break;
    case 0x92:
      printf("MOV %02x,C", get_value(pc + 1));
      pc += 2;
      break;
    case 0xA5:
      printf("TRAP");
      pc += 1;
      break;
    default:
      if ((opcode & 0x1F) == 0x11) { // XXX1 0001 & 0001 1111 = 0001 0001
        printf("AJMP %04x", (((opcode >> 5) & 0x03) << 8) | get_value(pc + 1));
        pc += 2;
      } else if ((opcode & 0x0F) == 0x01) { // XXX0 0001 & 0001 1111 = 0000 0001
        printf("ACALL %04x", (((opcode >> 5) & 0x03) << 8) | get_value(pc + 1));
        pc += 2;
      } else {
        printf("未知指令：%02x\n", opcode);
        exit(1);
      }
    }
    printf("\n");
  }
}
